package com.imut.lagain.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.imut.lagain.entity.MemoryCapsule;
import com.imut.lagain.entity.User;
import com.imut.lagain.service.IMemoryCapsuleService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.concurrent.CompletableFuture;

/**
 * 定时任务服务类
 * 处理各种定时任务
 */
@Service
public class ScheduleService {
    private static final Logger log = LoggerFactory.getLogger(ScheduleService.class);

    
    private final IMemoryCapsuleService memoryCapsuleService;
    private final IUserService userService;
    private final IEmailService emailService;
    private final ISmsService smsService;
    
    @Autowired(required = false)
    private ICacheService cacheService;
    
    public ScheduleService(IMemoryCapsuleService memoryCapsuleService, IUserService userService, 
                          IEmailService emailService, ISmsService smsService) {
        this.memoryCapsuleService = memoryCapsuleService;
        this.userService = userService;
        this.emailService = emailService;
        this.smsService = smsService;
    }
    /**
     * 检查即将开启的胶囊（每小时执行一次）
     */
    @Scheduled(cron = "0 0 * * * ?")
    @Transactional
    public void checkCapsulesAboutToOpen() {
        try {
            LocalDateTime now = LocalDateTime.now();
            LocalDateTime tomorrow = now.plusDays(1);
            
            List<MemoryCapsule> capsulesAboutToOpen = memoryCapsuleService.findCapsulesAboutToOpen(now, tomorrow);
            
            for (MemoryCapsule capsule : capsulesAboutToOpen) {
                try {
                    long hoursLeft = ChronoUnit.HOURS.between(now, capsule.getOpenTime());
                    if (hoursLeft == 24 || hoursLeft == 12 || hoursLeft == 6 || hoursLeft == 1) {
                        sendCapsuleOpenReminder(capsule, hoursLeft);
                    }
                } catch (Exception e) {
                    log.error("处理胶囊开启提醒失败: capsuleId={}", capsule.getId(), e);
                }
            }
            
            log.info("胶囊开启提醒检查完成，处理了{}个胶囊", capsulesAboutToOpen.size());
        } catch (Exception e) {
            log.error("检查即将开启的胶囊失败", e);
        }
    }
    
    /**
     * 检查已到开启时间的胶囊（每分钟执行一次）
     */
    @Scheduled(cron = "0 * * * * ?")
    @Transactional
    public void checkCapsulesReadyToOpen() {
        try {
            log.debug("开始检查已到开启时间的胶囊");
            
            LocalDateTime now = LocalDateTime.now();
            List<MemoryCapsule> capsulesReadyToOpen = memoryCapsuleService.findCapsulesReadyToOpen(now);
            
            for (MemoryCapsule capsule : capsulesReadyToOpen) {
                try {
                    capsule.setStatus(3);
                    capsule.setActualOpenTime(now);
                    memoryCapsuleService.updateById(capsule);
                    sendCapsuleOpenNotification(capsule);
                    
                    log.info("胶囊已自动开启: id={}, title={}", capsule.getId(), capsule.getTitle());
                } catch (Exception e) {
                    log.error("处理胶囊自动开启失败: capsuleId={}", capsule.getId(), e);
                }
            }
            
            if (!capsulesReadyToOpen.isEmpty()) {
                log.info("胶囊自动开启检查完成，处理了{}个胶囊", capsulesReadyToOpen.size());
            }
        } catch (Exception e) {
            log.error("检查已到开启时间的胶囊失败", e);
        }
    }
    
    /**
     * 清理过期的临时胶囊（每天凌晨2点执行）
     */
    @Scheduled(cron = "0 0 2 * * ?")
    @Transactional
    public void cleanExpiredTempCapsules() {
        try {
            LocalDateTime expireTime = LocalDateTime.now().minusDays(30);
            List<MemoryCapsule> expiredCapsules = memoryCapsuleService.findExpiredTempCapsules(expireTime);
            
            int cleanedCount = 0;
            for (MemoryCapsule capsule : expiredCapsules) {
                try {
                    capsule.setIsDeleted(true);
                    capsule.setDeleteTime(LocalDateTime.now());
                    memoryCapsuleService.updateById(capsule);
                    
                    cleanedCount++;
                    log.debug("清理过期临时胶囊: id={}, title={}", capsule.getId(), capsule.getTitle());
                } catch (Exception e) {
                    log.error("清理过期临时胶囊失败: capsuleId={}", capsule.getId(), e);
                }
            }
        } catch (Exception e) {
            log.error("清理过期临时胶囊失败", e);
        }
    }
    /**
     * 清理非活跃用户（每周日凌晨3点执行）
     */
    @Scheduled(cron = "0 0 3 ? * SUN")
    @Transactional
    public void cleanInactiveUsers() {
        try {
            LocalDateTime inactiveTime = LocalDateTime.now().minusDays(180);
            List<User> inactiveUsers = userService.findInactiveUsers(inactiveTime);
            
            int cleanedCount = 0;
            for (User user : inactiveUsers) {
                try {
                    List<MemoryCapsule> userCapsules = memoryCapsuleService.findByUserIdAndStatus(user.getId(), "sealed");
                    
                    if (userCapsules.isEmpty()) {
                        user.setIsDeleted(true);
                        user.setDeleteTime(LocalDateTime.now());
                        userService.updateById(user);
                        
                        cleanedCount++;
                        log.debug("清理非活跃用户: id={}, nickname={}", user.getId(), user.getNickname());
                    }
                } catch (Exception e) {
                    log.error("清理非活跃用户失败: userId={}", user.getId(), e);
                }
            }
        } catch (Exception e) {
            log.error("清理非活跃用户失败", e);
        }
    }
    
    /**
     * 更新用户活跃度统计（每天凌晨1点执行）
     */
    @Scheduled(cron = "0 0 1 * * ?")
    @Transactional
    public void updateUserActivityStats() {
        try {
            LocalDateTime yesterday = LocalDateTime.now().minusDays(1);
            LocalDateTime today = LocalDateTime.now();
            long activeUserCount = userService.countActiveUsers(yesterday, today);
            long newUserCount = userService.countNewUsers(yesterday, today);
            String dateKey = yesterday.toLocalDate().toString();
            if (cacheService != null) {
                cacheService.hSet("user:stats:" + dateKey, "activeUsers", activeUserCount);
                cacheService.hSet("user:stats:" + dateKey, "newUsers", newUserCount);
            }
        } catch (Exception e) {
            log.error("更新用户活跃度统计失败", e);
        }
    }
    /**
     * 清理过期缓存（每小时执行一次）
     */
    @Scheduled(cron = "0 30 * * * ?")
    public void cleanExpiredCache() {
        try {
            if (cacheService != null) {
                log.debug("开始清理过期缓存");
                cacheService.cleanExpiredCache();
                log.debug("过期缓存清理完成");
            }
        } catch (Exception e) {
            log.error("清理过期缓存失败", e);
        }
    }
    
    /**
     * 生成系统统计报告（每天凌晨4点执行）
     */
    @Scheduled(cron = "0 0 4 * * ?")
    public void generateSystemStats() {
        try {
            LocalDateTime now = LocalDateTime.now();
            String dateKey = now.toLocalDate().toString();
            long totalCapsules = memoryCapsuleService.count();
            long sealedCapsules = memoryCapsuleService.countByStatus("sealed");
            long openedCapsules = memoryCapsuleService.countByStatus("opened");
            long totalUsers = userService.count();
            long activeUsers = userService.countActiveUsers();
            cacheService.hSet("system:stats:" + dateKey, "totalCapsules", totalCapsules);
            cacheService.hSet("system:stats:" + dateKey, "sealedCapsules", sealedCapsules);
            cacheService.hSet("system:stats:" + dateKey, "openedCapsules", openedCapsules);
            cacheService.hSet("system:stats:" + dateKey, "totalUsers", totalUsers);
            cacheService.hSet("system:stats:" + dateKey, "activeUsers", activeUsers);
        } catch (Exception e) {
            log.error("生成系统统计报告失败", e);
        }
    }
    
    /**
     * 清理系统日志（每周一凌晨5点执行）
     */
    @Scheduled(cron = "0 0 5 ? * MON")
    public void cleanSystemLogs() {
        try {
            LocalDateTime expireTime = LocalDateTime.now().minusDays(30);
            LocalDateTime operationExpireTime = LocalDateTime.now().minusDays(90);
        } catch (Exception e) {
            log.error("清理系统日志失败", e);
        }
    }
    /**
     * 异步发送胶囊开启提醒
     * @param capsule 胶囊
     * @param hoursLeft 剩余小时数
     */
    @Async
    public CompletableFuture<Void> sendCapsuleOpenReminder(MemoryCapsule capsule, long hoursLeft) {
        return CompletableFuture.runAsync(() -> {
            try {
                User user = userService.getById(capsule.getUserId());
                if (user == null) {
                    log.warn("用户不存在，无法发送胶囊开启提醒: userId={}", capsule.getUserId());
                    return;
                }
                // Email功能已移除
                log.debug("胶囊开启提醒: 用户={}, 胶囊={}, 剩余{}小时", user.getNickname(), capsule.getTitle(), hoursLeft);
                if (user.getPhone() != null && smsService.isSmsServiceAvailable()) {
                    String openTimeStr = capsule.getOpenTime().format(
                        java.time.format.DateTimeFormatter.ofPattern("MM-dd HH:mm")
                    );
                    smsService.sendCapsuleReminder(user.getPhone(), capsule.getTitle(), openTimeStr);
                }
                
                log.info("胶囊开启提醒发送完成: capsuleId={}, hoursLeft={}", capsule.getId(), hoursLeft);
            } catch (Exception e) {
                log.error("发送胶囊开启提醒失败: capsuleId={}", capsule.getId(), e);
            }
        });
    }
    
    /**
     * 异步发送胶囊开启通知
     * @param capsule 胶囊
     */
    @Async
    public CompletableFuture<Void> sendCapsuleOpenNotification(MemoryCapsule capsule) {
        return CompletableFuture.runAsync(() -> {
            try {
                User user = userService.getById(capsule.getUserId());
                if (user == null) {
                    log.warn("用户不存在，无法发送胶囊开启通知: userId={}", capsule.getUserId());
                    return;
                }
                // Email功能已移除
                log.debug("胶囊开启通知: 用户={}, 胶囊={}", user.getNickname(), capsule.getTitle());
                
                log.info("胶囊开启通知发送完成: capsuleId={}", capsule.getId());
            } catch (Exception e) {
                log.error("发送胶囊开启通知失败: capsuleId={}", capsule.getId(), e);
            }
        });
    }
    
    /**
     * 异步备份重要数据
     */
    @Async
    public CompletableFuture<Void> backupImportantData() {
        return CompletableFuture.runAsync(() -> {
            try {
            } catch (Exception e) {
                log.error("备份重要数据失败", e);
            }
        });
    }
    /**
     * 手动触发胶囊开启检查
     */
    public void manualCheckCapsules() {
        checkCapsulesReadyToOpen();
        checkCapsulesAboutToOpen();
    }
    
    /**
     * 手动触发缓存清理
     */
    public void manualCleanCache() {
        cleanExpiredCache();
    }
    
    /**
     * 手动生成统计报告
     */
    public void manualGenerateStats() {
        generateSystemStats();
        updateUserActivityStats();
    }
    
    /**
     * 获取定时任务状态
     * @return 任务状态信息
     */
    public java.util.Map<String, Object> getScheduleStatus() {
        java.util.Map<String, Object> status = new java.util.HashMap<>();
        
        try {
            status.put("lastCapsuleCheck", LocalDateTime.now());
            status.put("emailServiceAvailable", emailService.isEmailServiceAvailable());
            status.put("smsServiceAvailable", smsService.isSmsServiceAvailable());
            String today = LocalDateTime.now().toLocalDate().toString();
            Object todayStats = cacheService.hGetAll("system:stats:" + today);
            status.put("todayStats", todayStats);
            
        } catch (Exception e) {
            log.error("获取定时任务状态失败", e);
            status.put("error", e.getMessage());
        }
        
        return status;
    }
}

